#ifndef PW_PBL_FRAME_HPP
#define PW_PBL_FRAME_HPP

#include "TLSF/string.hpp"
#include <string>
#include <span>
#include <string_view>
#include <tuple>
#include "dst.hpp"
#include "BitEnum.hpp"

namespace pw_pbl::Frame
{
	template <typename IMP, typename LOWLEVEL>
	class Builder;

	template <typename T>
	concept ccDerivedBuilder = requires {
		Builder{std::declval<T>()}; // 支持自动推导出模板参数
	};

	template <typename T>
	concept ccRawBuilder = !ccDerivedBuilder<T>;

	/// 帧构建器约束
	template <typename IMP>
	concept ccBuilder = ccDerivedBuilder<IMP> && requires(IMP &imp) {
		{
			imp.HeaderSize()
		} -> std::integral; // 获取帧头长度，必须定义
		{
			imp.TailerSize()
		} -> std::integral; // 获取帧尾长度，必须定义，主要用于构造时预保留空间，构造后未分配，不为0时应在EndWrite中分配
		imp.EndWrite();		// 结束一帧的写入，可选定义，自定义时本层操作结束后需调用Builder模板的EndWrite
	};

	/// 中级帧构建器约束，除标准约束外还要求有标准形式构造函数
	template <typename IMP>
	concept ccMiddleBuilder = ccBuilder<IMP> && requires {
		IMP(std::declval<typename IMP::TOption>(), std::declval<typename IMP::TLowLevelParms>(), size_t(0), size_t(0)); // 必须有标准形式构造函数，未定义TOption时可使用Builder模板的回退定义
	};

	template <typename T>
	struct RawBuilderTraits;

	template <typename T> requires std::same_as<typename T::value_type, char>
	struct RawBuilderTraits<T>
	{
		/// 直接设置内容大小并预留空间，在有效长度内的内容不变，注意此操作前对内容的引用语义对象失效
		/// @note 要求size <= capacity
		static inline constexpr void SetSize(T &lowest, size_t size, size_t capacity) noexcept
		{
			if constexpr (requires { lowest.resize_and_overwrite(capacity, [](auto...) { return size_t(0); }); })
				lowest.resize_and_overwrite(capacity, [size](auto...) { return size; });
			else if (size <= lowest.size())
			{
				lowest.resize(size);
				lowest.reserve(capacity);
			}
			else
			{
				lowest.reserve(capacity);
				lowest.resize(size);
			}
		}

		/// 构造原始帧对象
		static inline constexpr T Construct(size_t size, size_t capacity) noexcept
		{
			T buf{};
			if constexpr (requires { buf.resize_and_overwrite(capacity, [](auto...) { return size_t(0); }); })
				buf.resize_and_overwrite(std::max(size, capacity), [size](auto...) { return size; });
			else
			{
				buf.reserve(std::max(size, capacity));
				buf.resize(size);
			}
			return buf;
		}
	};
	template <typename T>
	struct RawBuilderTraits<T &> : public RawBuilderTraits<T>
	{
	};

	template <typename... P>
	struct RawBuilderTraits<TLSF::basic_string<char, P...>>
	{
		using T = TLSF::basic_string<char, P...>;

		/// 直接设置内容大小并预留空间，在有效长度内的内容不变，注意此操作前对内容的引用语义对象失效
		/// @note 要求size <= capacity
		static inline constexpr void SetSize(T &lowest, size_t size, size_t capacity) noexcept { lowest.resize_for_overwrite(size, capacity); }

		/// 构造原始帧对象
		static inline constexpr T Construct(size_t size, size_t capacity) noexcept { return T{size, capacity}; }
	};

	namespace _frame
	{
		using ttEmptyTuple = std::tuple<>;

		template <ccDerivedBuilder IMP>
		struct ttBuilderTraits : public ttBuilderTraits<decltype(Builder{std::declval<IMP>()})>
		{
		};
		template <typename IMP, typename LOWLEVEL>
		struct ttBuilderTraits<Builder<IMP, LOWLEVEL>>
		{
			using ContructorParms = std::pair<typename IMP::TOption, typename IMP::TLowLevelParms>;
			static constexpr typename IMP::TOption first(ContructorParms &&parms) { return std::forward<ContructorParms>(parms).first; }
			static constexpr typename IMP::TLowLevelParms second(ContructorParms &&parms) { return std::forward<ContructorParms>(parms).second; }
		};
		template <typename IMP, ccRawBuilder LOWLEVEL>
		struct ttBuilderTraits<Builder<IMP, LOWLEVEL>>
		{
			using ContructorParms = typename IMP::TOption;
			static constexpr typename IMP::TOption first(ContructorParms &&parms) { return std::forward<ContructorParms>(parms); }
			static constexpr ttEmptyTuple second(ContructorParms &&) { return {}; }
		};
		template <typename IMP, typename LOWLEVEL>
		struct ttBuilderTraits<Builder<IMP, LOWLEVEL &>>
		{
			using ContructorParms = std::pair<typename IMP::TOption, LOWLEVEL &>;
			static constexpr typename IMP::TOption first(ContructorParms &&parms) { return std::forward<ContructorParms>(parms).first; }
			static constexpr LOWLEVEL &second(ContructorParms &&parms) { return std::forward<ContructorParms>(parms).second; }
		};

		template <typename FRAME>
		using ContructorParms = typename ttBuilderTraits<FRAME>::ContructorParms;

		template <typename IMP, typename LOWLEVEL>
		struct Container
		{
			LOWLEVEL _lowLevel;

			inline constexpr IMP &_self() noexcept
			{
				static_assert(ccBuilder<IMP>);
				return *static_cast<IMP *>(this);
			}
			inline constexpr auto _headerSize() noexcept { return _self().HeaderSize(); }
			inline constexpr auto _tailerSize() noexcept { return _self().TailerSize(); }
			// 直接设置内容大小并预留空间，在有效长度内的内容不变，注意此操作前对内容的引用语义对象失效
			inline constexpr void _setSize(size_t size, size_t capacity) noexcept
			{
				if constexpr (ccDerivedBuilder<LOWLEVEL>)
					_lowLevel._setSize(_headerSize() + size, _headerSize() + _tailerSize() + capacity);
				else
					RawBuilderTraits<LOWLEVEL>::SetSize(_lowLevel, _headerSize() + size, _headerSize() + _tailerSize() + capacity);
			}
		};

		template <typename IMP, typename LOWLEVEL>
		class Constructor : public Container<IMP, LOWLEVEL>
		{
			using Base = Container<IMP, LOWLEVEL>;

		public:
			using TLowLevelParms = ContructorParms<LOWLEVEL>;
			inline constexpr Constructor(TLowLevelParms lp, size_t size, size_t capacity) noexcept
				: Base{._lowLevel{ttBuilderTraits<LOWLEVEL>::first(std::forward<TLowLevelParms>(lp)), ttBuilderTraits<LOWLEVEL>::second(std::forward<TLowLevelParms>(lp)), Base::_headerSize() + size, Base::_headerSize() + Base::_tailerSize() + capacity}} {}
		};

		template <typename IMP, ccRawBuilder LOWLEVEL>
		class Constructor<IMP, LOWLEVEL> : public Container<IMP, LOWLEVEL>
		{
			using Base = Container<IMP, LOWLEVEL>;

		public:
			using TLowLevelParms = ttEmptyTuple;
			inline constexpr Constructor(TLowLevelParms, size_t size, size_t capacity) noexcept
				: Base{._lowLevel{RawBuilderTraits<LOWLEVEL>::Construct(Base::_headerSize() + size, Base::_headerSize() + Base::_tailerSize() + capacity)}} {}
		};

		template <typename IMP, typename LOWLEVEL>
		class Constructor<IMP, LOWLEVEL &> : public Container<IMP, LOWLEVEL &>
		{
			using Base = Container<IMP, LOWLEVEL &>;

		public:
			using TLowLevelParms = LOWLEVEL &;
			inline constexpr Constructor(LOWLEVEL &L, size_t size, size_t capacity) noexcept
				: Base{._lowLevel{L}} { Base::_setSize(size, std::max(size, capacity)); }
		};
	} // namespace _frame

	/// 数据帧构建类，对外主要表现为信息内容的string，与std::string相同的操作以小写字母开头，否则以大写字母开头
	/// @tparam IMP 具体帧的实现类，必须由本类派生，且满足ccBuilder。通常实现为:
	///				template<typename LOWLEVEL>
	///				struct IMP : public Builder<IMP, LOWLEVEL> {
	///					using TBuilder = Builder<IMP, LOWLEVEL>;
	///					using typename TBuilder::TLowLevelParms;
	///					using TBuilder::TBuilder; // 本层没有构造参数时，可直接使用模板构造函数
	///					using TOption = ...; 		// 定义本层构造参数，则必须定义构造函数
	///					IMP(TOption opt, TLowLevelParms lp, size_t sz, size_t cap) : TBuilder(std::forward<TLowLevelParms>(lp), sz, cap); // 添加本层参数的构造函数
	///					constexpr size_t HeaderSize() noexcept { return 0; }		// 必须定义帧头长度
	///					constexpr size_t TailerSize() noexcept { return 0; }		// 必须定义帧尾长度
	///				};
	/// @tparam LOWLEVEL 低一层的帧类型，一般是本模板类或RawFrame
	/// @note 除非特别指定，操作均在信息内容区进行，与字符相关的索引、长度相关的值表示为信息内容区，不含帧头和帧尾
	template <typename IMP, typename LOWLEVEL = std::string>
	class Builder : public _frame::Constructor<IMP, LOWLEVEL>
	{
		template <typename OTHERI, typename OTHERL>
		friend class Builder;
		template <typename OTHERI, typename OTHERL>
		friend struct _frame::Container;

		using Constructor = _frame::Constructor<IMP, LOWLEVEL>;
		using Constructor::_headerSize;
		using Constructor::_lowLevel;
		using Constructor::_setSize;
		using Constructor::_tailerSize;

	protected:
		/// 复归帧内容和帧头区，注意帧头区内容清除但其在底层区占用的空间仍有效，可用于写入帧头数据
		inline constexpr void FullReset(size_t capacity) noexcept
		{
			_lowLevel.clear();	   // 连帧头一起清除，减少复制
			_setSize(0, capacity); // 设置大小，注意已经在低层帧设置了帧头大小
		}

	public:
		using TOption = std::tuple<>;
		using Constructor::Constructor;
		using typename Constructor::TLowLevelParms;
		using TLowLevel = std::decay_t<LOWLEVEL>;

		/// 没有自定义参数时标准构造函数的回退实现
		/// @param opt 本层参数
		/// @param lp 低层参数
		/// @param sz 初始化长度
		/// @param cap 初始化容量
		inline constexpr Builder(TOption opt [[maybe_unused]], TLowLevelParms lp, size_t sz, size_t cap) requires std::same_as<typename IMP::TOption, TOption> : Constructor(std::forward<TLowLevelParms>(lp), sz, cap) {}

		template <typename QUERY = TLowLevel>
		inline constexpr decltype(auto) LowLevel() noexcept requires(std::same_as<QUERY, TLowLevel> || requires { _lowLevel.template LowLevel<QUERY>(); })
		{
			if constexpr (std::same_as<QUERY, TLowLevel>)
				return (_lowLevel); // 返回引用
			else
				return _lowLevel.template LowLevel<QUERY>();
		}

		inline constexpr decltype(auto) LowestLevel() noexcept
		{
			if constexpr (ccDerivedBuilder<LOWLEVEL>)
				return _lowLevel.LowestLevel();
			else
				return (_lowLevel);
		}

		template <typename QUERY>
		inline constexpr operator QUERY &() noexcept requires(requires { LowLevel<std::decay_t<QUERY>>(); }) { return LowLevel<std::decay_t<QUERY>>(); }

		template <typename CHAR = char>
		inline constexpr std::span<CHAR, std::dynamic_extent> Header() noexcept
		{
			static_assert(sizeof(CHAR) == sizeof(char));
			return {(CHAR *)_lowLevel.data(), _headerSize()};
		}

		inline constexpr std::string_view View() noexcept { return {data(), size()}; }

		inline constexpr void EndWrite() noexcept
		{
			if constexpr (ccDerivedBuilder<LOWLEVEL>)
				_lowLevel.EndWrite();
		}

	public:
		/// 在尾部添加对象，以FIELD fld{...};等效语法构造
		template <typename FIELD, typename... PMS>
		inline constexpr FIELD &Append(PMS &&...pms) noexcept
		{
			auto sz = size();
			resize(sz + sizeof(FIELD));
			return *new (&operator[](sz)) FIELD{std::forward<PMS>(pms)...};
		}

		/// 在尾部分配对象，以FIELD fld;等效语法构造（可能未初始化数据）
		template <typename FIELD>
		inline constexpr FIELD &AppendAlloc() noexcept
		{
			auto sz = size();
			resize(sz + sizeof(FIELD));
			return *new (data() + sz) FIELD;
		}

		/// 在尾部分配std::array<char,CNT>对象，以std::array<char,CNT> fld;等效语法构造（未初始化数据）
		template <size_t CNT>
		inline constexpr std::array<char, CNT> &AppendAlloc() noexcept { return AppendAlloc<std::array<char, CNT>>(); }

		/// 在指定位置插入分配未初始化数据
		inline constexpr std::span<char> InsertAlloc(size_t pos, size_t count) noexcept
		{
			auto orgsize = size();
			if (orgsize > pos)
			{
				resize(orgsize + count);
				std::copy_backward(data() + pos, data() + orgsize, data() + orgsize + count);
			}
			else
				resize(pos + count);
			return {data() + pos, count};
		}

		/// 在指定位置插入分配对象，以FIELD fld;等效语法构造（可能未初始化数据）
		template <typename FIELD>
		inline constexpr FIELD &InsertAlloc(size_t pos) noexcept { return *new (InsertAlloc(pos, sizeof(FIELD)).data()) FIELD; }

		/// 在指定位置插入分配std::array<char,CNT>对象，以std::array<char,CNT> fld;等效语法构造（未初始化数据）
		template <size_t CNT>
		inline constexpr std::array<char, CNT> &InsertAlloc(size_t pos) noexcept { return InsertAlloc<std::array<char, CNT>>(pos); }

	public:
		/// 复归帧内容，帧头区数据不变，注意此操作前对内容的引用语义对象失效
		inline constexpr void clear() noexcept { resize(0); }

		/// 预先保留至少指定大小的空间后续用于存储内容，但不改变当前内容大小，注意此操作前对内容的引用语义对象失效
		inline constexpr void reserve(size_t capacity) noexcept { _lowLevel.reserve(_headerSize() + _tailerSize() + capacity); }

		/// 返回当前内容大小
		inline constexpr std::size_t size(void) noexcept { return _lowLevel.size() - _headerSize(); }

		/// 直接设置内容大小，注意此操作前对内容的引用语义对象失效
		inline constexpr void resize(size_t size) noexcept { _setSize(size, size); }

		template <typename... P>
		inline constexpr void replace(size_t pos, size_t count, P &&...p) noexcept { _lowLevel.replace(pos + _headerSize(), count, std::forward<P>(p)...); }

		/// 在尾部批量添加字符，会增加内容大小，注意此操作前对内容的引用语义对象失效
		template <typename... P>
		inline constexpr void append(P &&...p) noexcept { LowestLevel().append(std::forward<P>(p)...); }

		/// 在尾部添加字符，会增加内容大小，注意此操作前对内容的引用语义对象失效
		template <typename P>
		inline constexpr void push_back(P &&p) noexcept { LowestLevel().push_back(std::forward<P>(p)); }

		/// 返回指定偏移的数据引用，注意大小相关操作后失效
		inline constexpr auto &operator[](size_t i) noexcept { return data()[i]; }

		/// 返回内容的首字符
		inline constexpr char *data() noexcept { return _lowLevel.data() + _headerSize(); }

		/// 返回数据的视图引用，注意大小相关操作后失效
		template <typename... P>
		inline constexpr operator std::basic_string_view<P...>(void) noexcept { return {data(), size()}; }
	};

	template <typename BODY>
	constexpr auto len_of = std::is_empty_v<BODY> ? 0 : sizeof(BODY);

	template <typename ELE>
	constexpr auto len_of<ELE[]> = 0;

	template <typename...>
	struct PlainView;

	namespace _frame
	{
		template <typename BODY>
		struct BodyTraits
		{
			static constexpr auto EHeaderLen = 0;
			static constexpr auto ETailerLen = 0;
			using raw = BODY;
		};

		template <typename ELE>
		struct BodyTraits<ELE[]>
		{
			static constexpr auto EHeaderLen = 0;
			static constexpr auto ETailerLen = 0;
			using raw = SliceDst<ELE>;
		};

		template <typename BODY>
		struct BodyTraits<PlainView<BODY>>
		{
			static constexpr auto EHeaderLen = BodyTraits<BODY>::EHeaderLen;
			static constexpr auto ETailerLen = BodyTraits<BODY>::ETailerLen;
			using raw = BodyTraits<BODY>::raw;
		};

		template <typename HEADER, typename BODY>
		struct BodyTraits<PlainView<HEADER, BODY>>
		{
			static constexpr auto EHeaderLen = len_of<HEADER> + BodyTraits<BODY>::EHeaderLen;
			static constexpr auto ETailerLen = BodyTraits<BODY>::ETailerLen;
			using raw = BodyTraits<BODY>::raw;
		};

		template <typename HEADER, typename BODY, typename TAILER>
		struct BodyTraits<PlainView<HEADER, BODY, TAILER>>
		{
			static constexpr auto EHeaderLen = len_of<HEADER> + BodyTraits<BODY>::EHeaderLen;
			static constexpr auto ETailerLen = len_of<TAILER> + BodyTraits<BODY>::ETailerLen;
			using raw = BodyTraits<BODY>::raw;
		};
	} // namespace _frame

	template <typename BODY>
	concept ccIsDstBody = ccIsSliceDst<typename _frame::BodyTraits<BODY>::raw>;

	template <typename BODY>
	using ttDstElement = typename decltype(SliceDst{std::declval<typename _frame::BodyTraits<BODY>::raw>()})::element_type;

	template <typename BODY>
	struct PlainView<BODY> : private std::string_view
	{
	private:
		using TBodyTraits = _frame::BodyTraits<BODY>;
		using TBody = TBodyTraits::raw;
		static constexpr auto EHeaderLen = TBodyTraits::EHeaderLen;
		static constexpr auto EBodyLen = len_of<TBody>;
		static constexpr auto ETailerLen = TBodyTraits::ETailerLen;

	public:
		constexpr PlainView(std::string_view raw) noexcept requires(!ccIsSliceDst<TBody>) : std::string_view(raw.size() == EBodyLen ? raw : std::string_view{}) {}
		constexpr PlainView(std::string_view raw) noexcept requires ccIsSliceDst<TBody> : std::string_view(raw.size() >= EBodyLen ? raw : std::string_view{}) {}
		explicit constexpr operator bool() const { return this->data() != nullptr; }
		inline auto &Header() const { return *reinterpret_cast<const std::tuple<> *>(this->data()); }
		inline const BODY &Body() const { return *reinterpret_cast<const BODY *>(this->data()); }
		inline auto &Tailer() const { return *reinterpret_cast<const std::tuple<> *>(this->end()); }
		constexpr std::string_view PlainBody() const requires ccIsSliceDst<TBody> && (EBodyLen == 0) { return *this; }
		constexpr size_t ElementCnt() const requires ccIsSliceDst<TBody> { return this->size() - EBodyLen; }

		template <typename... T>
		constexpr PlainView(PlainView<T...> raw) noexcept : std::string_view(raw.PlainBody()) {}
	};

	template <typename HEADER, typename BODY>
	struct PlainView<HEADER, BODY> : private std::string_view
	{
	private:
		using TBodyTraits = _frame::BodyTraits<BODY>;
		using TBody = TBodyTraits::raw;
		static constexpr auto EHeaderLen = len_of<HEADER> + TBodyTraits::EHeaderLen;
		static constexpr auto EBodyLen = len_of<TBody>;
		static constexpr auto ETailerLen = TBodyTraits::ETailerLen;

	public:
		constexpr PlainView(std::string_view raw) noexcept requires(!ccIsSliceDst<TBody>) : std::string_view(raw.size() == EHeaderLen + EBodyLen ? raw.substr(EHeaderLen) : std::string_view{}) {}
		constexpr PlainView(std::string_view raw) noexcept requires ccIsSliceDst<TBody> : std::string_view(raw.size() >= EHeaderLen + EBodyLen ? raw.substr(EHeaderLen) : std::string_view{}) {}
		explicit constexpr operator bool() const { return this->data() != nullptr; }
		inline const HEADER &Header() const { return *reinterpret_cast<const HEADER *>(this->data() - EHeaderLen); }
		inline const BODY &Body() const { return *reinterpret_cast<const BODY *>(this->data()); }
		inline auto &Tailer() const { return *reinterpret_cast<const std::tuple<> *>(this->end()); }
		constexpr std::string_view PlainBody() const requires ccIsSliceDst<TBody> && (EBodyLen == 0) { return *this; }
		constexpr size_t ElementCnt() const requires ccIsSliceDst<TBody> { return this->size() - EBodyLen; }

		template <typename... T>
		constexpr PlainView(PlainView<T...> raw) noexcept : std::string_view(raw.PlainBody()) {}
	};

	template <typename HEADER, typename BODY, typename TAILER>
	struct PlainView<HEADER, BODY, TAILER> : private std::string_view
	{
	private:
		using TBodyTraits = _frame::BodyTraits<BODY>;
		using TBody = TBodyTraits::raw;
		static constexpr auto EHeaderLen = len_of<HEADER> + TBodyTraits::EHeaderLen;
		static constexpr auto EBodyLen = len_of<TBody>;
		static constexpr auto ETailerLen = len_of<TAILER> + TBodyTraits::ETailerLen;

	public:
		constexpr PlainView(std::string_view raw) noexcept requires(!ccIsSliceDst<TBody>) : std::string_view(raw.size() == EHeaderLen + EBodyLen + ETailerLen ? raw.substr(EHeaderLen, EBodyLen) : std::string_view{}) {}
		constexpr PlainView(std::string_view raw) noexcept requires ccIsSliceDst<TBody> : std::string_view(raw.size() >= EHeaderLen + EBodyLen + ETailerLen ? raw.substr(EHeaderLen, raw.size() - EHeaderLen - ETailerLen) : std::string_view{}) {}
		explicit constexpr operator bool() const { return this->data() != nullptr; }
		inline const HEADER &Header() const { return *reinterpret_cast<const HEADER *>(this->data() - EHeaderLen); }
		inline const BODY &Body() const { return *reinterpret_cast<const BODY *>(this->data()); }
		inline const TAILER &Tailer() const { return *reinterpret_cast<const TAILER *>(this->end()); }
		constexpr std::string_view PlainBody() const requires ccIsSliceDst<TBody> && (EBodyLen == 0) { return *this; }
		constexpr size_t ElementCnt() const requires ccIsSliceDst<TBody> { return this->size() - EBodyLen; }

		template <typename... T>
		constexpr PlainView(PlainView<T...> raw) noexcept : std::string_view(raw.PlainBody()) {}
	};

	template <typename... IDS> requires(ccDuckEnum<IDS> && ...)
	struct MergedID;

	template <typename STD, typename EXT> requires std::same_as<pw_pbl::underlying_type_t<STD>, pw_pbl::underlying_type_t<EXT>>
	struct MergedID<STD, EXT>
	{
		using Std = STD;
		using Ext = EXT;

		pw_pbl::underlying_type_t<Std> underlying;

		explicit constexpr MergedID(pw_pbl::underlying_type_t<Std> v) noexcept : underlying(v) {}
		constexpr MergedID(DuckEnumTraits<Std>::enum_type id) noexcept : underlying(pw_pbl::to_underlying(Std(id))) {}
		constexpr MergedID(DuckEnumTraits<Ext>::enum_type id) noexcept : underlying(pw_pbl::to_underlying(Ext(id))) {}
		constexpr operator Std() const { return Std{underlying}; }
		constexpr operator Ext() const { return Ext{underlying}; }

		constexpr Std to_std() const { return Std{underlying}; }
		constexpr Ext to_ext() const { return Ext{underlying}; }

		constexpr bool operator==(Std id) const { return underlying == pw_pbl::to_underlying(id); }
		constexpr bool operator==(Ext id) const { return underlying == pw_pbl::to_underlying(id); }
	};

} // namespace pw_pbl::Frame

#endif // PW_PBL_FRAME_HPP
